// 数据下载导出
const downloadStringAsFile = (data: any, filename: string, mimeType = 'text/plain') => {
  const blob = new Blob([data], { type: mimeType });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = filename;
  // 将 a 元素附加到 DOM 中
  document.body.appendChild(a);
  // 模拟点击链接以触发下载
  a.click();
  // 从 DOM 中移除 a 元素
  document.body.removeChild(a);
  // 释放对象 URL
  URL.revokeObjectURL(url);
}


const regexReader: any = {
  ext: /<ext>([\s\S]*?)<\/ext>/g,
  squareBrackets: /\[\[(.*?)\]\]/g,
  comment: /<!--([\s\S]*?)-->/g,
}

const removeContent = (content:string, tags: string[]) => {
  let res = content
  tags?.forEach(item => {
    if (regexReader[item]) {
      res = res.replace(regexReader[item], '')
    }
  })
  return res
}
const readTagContent = (content: string, tagName: string) => {
  const res: any[] = []
  if (!content || !regexReader[tagName]) {
    return res
  }
  let matcher = null
  while ((matcher = regexReader[tagName].exec(content)) !== null) {
    res.push(matcher[1])
  }
  return res
}

export default class Parser {
  private _content: string = ''

  public get content() {
    return this._content
  }

  public set content(value: string) {
    this._content = value
  }

  private buildTree = (rootEle: any, startNodeId: string | any) => {
    const childs = rootEle.getElementsByTagName('tw-passagedata')
    const childNodes: any[] = []
    let counter = 0
    const handleChild = (child: any) => {
      const title = child?.getAttribute('name')
      const content = child?.textContent.trim().replace(/[\r\n]/g, '')
      const ext = readTagContent(content, 'ext')
      let nodeId = child.getAttribute('pid')  // twine，pid: passage id,对应每一个文本节点id
      let extObj = null
      if (ext[0]) {
        extObj = JSON.parse(ext[0])
      }
      const edges = readTagContent(content, 'squareBrackets')
      const text = removeContent(content, ['comment', 'squareBrackets'])
      let row: any = {
        id: title, 
        content: text,
        nodeId: nodeId,
        type: 'TEXT',
        effect: ''
      }
      if (extObj) {
        row = {...extObj, ...row}
      }
      // 处理边
      const actionNode: any[] = []
      edges?.forEach(edge => {
        const splitIdx = edge.indexOf('->')
        if (splitIdx == -1) {
          return
        }
        const actionName = edge.slice(0, splitIdx)
        const nextId = edge.slice(splitIdx + 2)
        if (actionName == '继续') {
          // 默认包含一个继续按钮action，不处理。分支线保证不会出现继续作为选项
          row.next = nextId
          return;
        }
        actionNode.push({
          id: 'action_' + ++counter,
          type: 'ACTION',
          effect: '',
          content: actionName,
          next: nextId
        })
      })
      if (actionNode.length > 0) {
        row.next = actionNode.map(item => item.id).join('@')
      }
      childNodes.push(row)
      childNodes.push(...actionNode)
    }
    // 读取节点
    for (let childIdx = 0; childIdx < childs.length; childIdx++) {
      handleChild(childs[childIdx])
    }
    console.log('childnodes:', childNodes)
    // arr to obj
    const childObj = childNodes.reduce((obj, curValue) => {
      obj[curValue.id] = curValue
      return obj
    }, {})
    // 构建节点树
    const buildNode = (nodeObj: any, curNode: any) => {
      if (!curNode) {
        return
      }
      const nextIds = curNode.next
      const nextIdList = nextIds?.split('@')
      curNode.children = nextIdList?.map((id: any) => nodeObj[id])
      curNode.children?.forEach((item: any) => buildNode(nodeObj, item))
    }
    const startNode = Object.values(childObj).filter((item: any) => item.nodeId ==startNodeId)[0]
    buildNode(childObj, startNode)
    return startNode
  } 

  public parseToCsvData() {
    const parser = new DOMParser()
    const doc = parser.parseFromString(this.content, 'text/html')
    const rootTag = 'tw-storydata'
    const rootEle = doc.getElementsByTagName(rootTag)[0]
    if (rootEle) {
      const tree = {
        rootNodeId: rootEle.getAttribute('startnode'),
        creatorVersion: rootEle.getAttribute('creator-version'),
        rootNode: this.buildTree(rootEle, rootEle.getAttribute('startnode'))
      }
      // 转换为CSV格式数据（每个节点对应一行
      const res: any = []
      const toCsvValue = (obj: any) => {
      if (!obj) {
        return ''
      }
      return obj
      }
      const treeToCsv = (root: any, res: any[]) => {
        if (!root) {
          return
        }
        res.push({
          id: toCsvValue(root.id),
          role_id: toCsvValue(root.role_id),
          role_name: toCsvValue(root.role_name),
          type: toCsvValue(root.type),
          position: toCsvValue(root.position),
          next: toCsvValue(root.next),
          content: toCsvValue(root.content),
          effect: toCsvValue(root.effect),
          condition_rules: toCsvValue(root.condition_rules),
          target: toCsvValue(root.target)
        })
        root?.children?.forEach((node: any) => treeToCsv(node, res))
      }
      treeToCsv(tree.rootNode, res)
      return res
    }
    return ''
  }

  public downloadData = () => {
    const res = this.parseToCsvData()
    const saveDataToCsv = (rows: any[], headers: string[], types: string[], labels: string[]) => {
      const dataRows = rows?.map(row => {
        const tmpList: any[] = []
        headers?.forEach(key => {
          row[key] !== undefined && row[key] !== null && tmpList.push(row[key])
        })
        return tmpList.join(',')
      })
      const str = [headers.join(','), types.join(','), labels.join(','), ...dataRows].join('\n')
      downloadStringAsFile(str, 'data.csv')
    }
    const headers = ['id', 'type', 'role_id', 'role_name', 'position', 'content', 'next', 'effect', 'target', 'remark', 'condition_rule']
    const types = ['string', 'string', 'string', 'string', 'string', 'string', 'string', 'string', 'string', 'string', 'string']
    const labels = ['id', '类型', '角色id', '角色名', '对话框位置', '内容', '下一个', '效果', '目标', '备注', '该对话显示条件']
    saveDataToCsv(res, types, labels, headers)
  }
}